<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Frame;

use Srv\Libs\Exception\PoolItemMysqlException;
use Srv\Libs\Exception\PoolItemRedisException;
use Srv\Libs\Pools\Pool;
use Srv\Libs\Storage\DataMysql;
use Srv\Libs\Storage\DataRedis;
use Swoole\Server;

abstract class ControllerAbstract
{
    protected static array $tagObjectList                   = [];           // TAG对象列表
    private const TAG_DEFAULT_NAME                          = 'NULL';       // TAG默认名
    private const GROUP_NAME_CACHE_AUTO                     = 'auto';       // CACHE组名AUTO
    private const GROUP_NAME_CACHE_API                      = 'api';        // CACHE组名API
    private const GROUP_NAME_DB_AUTO                        = 'auto';       // DB组名AUTO
    private const GROUP_NAME_DB_READ                        = 'read';       // DB组名READ
    private static ?DataRedis $DataRedis                    = null;         // Cache
    private static ?DataRedis $DataRedisApi                 = null;         // Cache-Api
    private static ?DataMysql $DataMysqlAuto                = null;         // DB-Write
    private static ?DataMysql $DataMysqlRead                = null;         // DB-Read

    /**
     * @return mixed
     * 对象获取
     */
    abstract public static function tag();

    /**
     * @param string $tagStr
     * @param string $className
     * @return string
     * 获取Tag名称
     */
    private static function getTagName(string $tagStr, string $className):string
    {
        return $className.(strlen($tagStr) < 1 ? self::TAG_DEFAULT_NAME : $tagStr);
    }

    /**
     * @param string $tagStr
     * @return mixed
     * 获取标签的对象
     */
    final protected static function tagGet(string $tagStr = '')
    {
        $__class__      = static::class;
        $tagName        = self::getTagName($tagStr, $__class__);
        if(isset(self::$tagObjectList[$tagName])) return self::$tagObjectList[$tagName];
        $tagObject                      = new $__class__();
        self::$tagObjectList[$tagName]  = $tagObject;
        return self::$tagObjectList[$tagName];
    }

    /**
     * @param string $tagStr
     * @return bool
     * 删除标签的对象
     */
    final public static function tagDelete(string $tagStr):bool
    {
        $__class__      = static::class;
        $tagName        = self::getTagName($tagStr, $__class__);
        if(isset(self::$tagObjectList[$tagName])){
            unset(self::$tagObjectList[$tagName]);
            return !isset(self::$tagObjectList[$tagName]);
        }
        return true;
    }

    /**
     * 清除全部的对象
     */
    final public static function tagClear():void
    {
        self::$tagObjectList    = [];
    }

    /**
     * @return Server|null
     * getWebSocketServer
     */
    final public static function getWebSocketServer():?Server
    {
        return ActionAbstract::getWebSocketServer();
    }

    /**
     * @return int
     * getWebSocketFd
     */
    final public static function getWebSocketFd():int
    {
        return ActionAbstract::getWebSocketFd();
    }

    /**
     * @return string
     * getServerName
     */
    final public static function getServerName():string
    {
        return ActionAbstract::getServerName();
    }

    /**
     * @return bool
     * isRelease
     */
    final public static function isRelease():bool
    {
        return ActionAbstract::isRelease();
    }

    /**
     * @param string $logString
     * @return void
     * addRunLog
     */
    final public static function addRunLog(string $logString):void
    {
        ActionAbstract::addRunLog($logString);
    }

    /**
     * @param $logData
     * @return void
     * addRunLogData
     */
    final public static function addRunLogData($logData):void
    {
        ActionAbstract::addRunLogData($logData);
    }

    /**
     * @return string
     * getRootPath
     */
    final public static function getRootPath():string
    {
        return ActionAbstract::getRootPath();
    }

    /**
     * @return string
     * getSrvPath
     */
    final public static function getSrvPath():string
    {
        return ActionAbstract::getSrvPath();
    }

    /**
     * @return string
     * getAppsPath
     */
    final public static function getAppsPath():string
    {
        return ActionAbstract::getAppsPath();
    }

    /**
     * @return string
     * getComposerPath
     */
    final public static function getComposerPath():string
    {
        return ActionAbstract::getComposerPath();
    }

    /**
     * @return string
     * getConfPath
     */
    final public static function getConfPath():string
    {
        return ActionAbstract::getConfPath();
    }

    /**
     * @return string
     * getLibsPath
     */
    final public static function getLibsPath():string
    {
        return ActionAbstract::getLibsPath();
    }

    /**
     * @return string
     * getDataPath
     */
    final public static function getDataPath():string
    {
        return ActionAbstract::getDataPath();
    }

    /**
     * @return string
     * getLogsPath
     */
    final public static function getLogsPath():string
    {
        return ActionAbstract::getLogsPath();
    }

    /**
     * @return string
     * getRouteGroupName
     */
    final public static function getRouteGroupName():string
    {
        return ActionAbstract::getRouteGroupName();
    }

    /**
     * @return string
     * getLangType
     */
    final public static function getLangType():string
    {
        return ActionAbstract::getLangType();
    }

    /**
     * @return DataRedis
     * getCacheAuto
     */
    final public static function getCacheAuto():DataRedis
    {
        if(Pool::isInit()){
            if(self::$DataRedis instanceof DataRedis && self::$DataRedis->isUse()) return self::$DataRedis;
            self::$DataRedis        = Pool::getDataRedisByGroup(self::GROUP_NAME_CACHE_AUTO);
        }else{
            self::$DataRedis        = DataRedis::tag(self::GROUP_NAME_CACHE_AUTO, 'CACHE_'.self::GROUP_NAME_CACHE_AUTO, self::GROUP_NAME_CACHE_AUTO);
        }
        return self::$DataRedis;
    }

    /**
     * @return DataRedis
     * getCacheApi
     */
    final public static function getCacheApi():DataRedis
    {
        if(Pool::isInit()){
            if(self::$DataRedisApi instanceof DataRedis && self::$DataRedisApi->isUse()) return self::$DataRedisApi;
            self::$DataRedisApi     = Pool::getDataRedisByGroup(self::GROUP_NAME_CACHE_API);
        }else{
            self::$DataRedisApi     = DataRedis::tag(self::GROUP_NAME_CACHE_API, 'CACHE_'.self::GROUP_NAME_CACHE_API, self::GROUP_NAME_CACHE_API);
        }
        return self::$DataRedisApi;
    }

    /**
     * @return DataMysql
     * getDbAuto
     */
    final public static function getDbAuto():DataMysql
    {
        if(Pool::isInit()){
            if(self::$DataMysqlAuto instanceof DataMysql && self::$DataMysqlAuto->isUse()) return self::$DataMysqlAuto;
            self::$DataMysqlAuto    = Pool::getDataMysqlByGroup(self::GROUP_NAME_DB_AUTO);
        }else{
            self::$DataMysqlAuto    = DataMysql::tag(self::GROUP_NAME_DB_AUTO, 'DB_'.self::GROUP_NAME_DB_AUTO, self::GROUP_NAME_DB_AUTO);
        }
        return self::$DataMysqlAuto;
    }

    /**
     * @return DataMysql
     * getDbRead
     */
    final public static function getDbRead():DataMysql
    {
        if(Pool::isInit()){
            if(self::$DataMysqlRead instanceof DataMysql && self::$DataMysqlRead->isUse()) return self::$DataMysqlRead;
            self::$DataMysqlRead    = Pool::getDataMysqlByGroup(self::GROUP_NAME_DB_READ);
        }else{
            self::$DataMysqlRead    = DataMysql::tag(self::GROUP_NAME_DB_READ, 'DB_'.self::GROUP_NAME_DB_READ, self::GROUP_NAME_DB_READ);
        }
        return self::$DataMysqlRead;
    }

    /**
     * @param string $nextKey
     * @param int $nextIndex
     * @return string
     * 生成Next分页值
     */
    final public function generateNext(string $nextKey, int $nextIndex):string
    {
        $next           = $nextKey.'-'.$nextIndex;
        return preg_match('/^[a-z\d]+-\d+$/i', $next) ? $next : '';
    }

    /**
     * @param string $next
     * @param string $nextKey
     * @param int $nextPos
     * @return bool
     * 解析Next分页值
     */
    final public function parseNext(string $next, string &$nextKey, int &$nextPos):bool
    {
        if(strlen($next) < 3) return false;
        if(preg_match('/^([a-z\d]+)-(\d+)$/i', $next, $match)){
            $nextKey    = $match[1];
            $nextPos    = intval($match[2]);
            return true;
        }
        return false;
    }
}